package cate.game.play.fighter;

import cate.common.table.d.*;
import cate.game.attr.FightAttr;
import cate.game.play.buff.Buff;
import cate.game.play.buff.BuffHandler;
import cate.game.play.proce.action.ctx.ActionCtx;
import cate.game.play.proce.play.PlayCtx;
import cate.game.play.proce.result.*;
import cate.game.play.skill.passive.PassiveHandler;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import easy.java.struct.ref.DoubleRef;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.annotation.Transient;

@NoteClass("战斗属性组")
@Slf4j
public class FightAttrGroup{

    @JsonIgnore
    @Transient
	public transient Fighter owner;

    @NoteField(value = "自身属性",detail = "战斗前拥有的自身属性，战斗中不会修改")
    @Getter
    private FightAttr self = new FightAttr();

    @NoteField(value = "战斗中的临时属性",detail = "属性增强和减弱的buff导致的属性变更存放于此")
    @Getter
    private FightAttr temp = new FightAttr();

    @NoteField(value = "单次行动中的临时属性")
    @JsonIgnore
    @Transient
    private FightAttr move = new FightAttr();

    @NoteField(value = "pvp生效的属性")
    private FightAttr pvp = new FightAttr();

    public void init(Fighter owner) {
        this.owner = owner;
    }

    public void beforeFight(PlayCtx playCtx) {
        if (playCtx.isPvP() && !pvp.isEmpty()) {
            self.add(pvp);
            pvp.clear();
        }
    }

    /**
     * 当前血量
     * @return
     */
    public double hpCur(){
        return self.hpCur();
    }

    /**
     * 设置当前血量
     * @return
     */
    public void hpCur(double value) {
        hpCur(value,null);
    }

    /**
     * 设置血量并且记录剧本
     * @param value
     * @param action
     */
    public void hpCur(double value, ActionCtx action) {
        self.hpCur(value);
        if (action != null) {
            action.addResult(new HpMaxChangeResult().pidSet(this.owner).hpSet(hpCur()).hpMaxSet(total().hpTotal()));
        }
    }


    //缓存的总属性
    private FightAttr cache = new FightAttr();
    //缓存属性是否失效
    private boolean cacheExpire = true;

    //标记缓存失效
    public void markCacheExpire(boolean cacheExpire) {
        this.cacheExpire = cacheExpire;
    }

    /**
     * 总攻击
     * @return
     */
    public double attTotal(){
        return total().attTotal();
    }

    /**
     * 合计属性
     */
    public FightAttr total() {
        if (cacheExpire) {
            cache.clear();
            cache.add(self);
            cache.add(temp);
            cache.add(move);
            markCacheExpire(false);
        }
        cache.hpCur(self.hpCur());
        return cache;
    }

    public void scale(double coeff) {
        self.scale(coeff);
        temp.scale(coeff);
        move.scale(coeff);
        pvp.scale(coeff);
        markCacheExpire(true);
    }

    public FightAttrGroup copy() {
        FightAttrGroup cp = new FightAttrGroup();
        cp.owner = this.owner;
        cp.self = this.self.copy();
        cp.temp = this.temp.copy();
        cp.move = this.move.copy();
        cp.pvp = this.pvp.copy();
        return cp;
    }

    //设置自身属性
    public void addSelfAttr(FightAttr attr) {
        self.add(attr);
    }

    public void addPvpAttr(FightAttr attr) {
        pvp.add(attr);
    }

    //被动技能伤害
    public DamageResult passiveHurt(ActionCtx action, Fighter actor, double v) {
        return passiveHurt(action, actor, v, GDSkill.Nature.NULL);
    }

    //带有性质的技能伤害
    public DamageResult passiveHurt(ActionCtx action, Fighter actor, double v, byte nature) {
        return skillHurt(action, actor, v, 0d, false, GDPlay.HpReason.PASSIVE_SKILL_HURT, nature);
    }

    //技能伤害(无视护盾 暴击 理由 性质)
    public DamageResult skillHurt(ActionCtx action, Fighter actor, double v, double ignShieldRate, boolean strike, int reason, byte nature) {
        return doSubHp(action, actor, v, ignShieldRate, new HpChangeResult().strikeSet(strike).reasonSet(reason).natureSet(nature));
    }

    //buff伤害
    public DamageResult buffHurt(ActionCtx action, Fighter actor, double v) {
        HpChangeResult result = new HpChangeResult().reasonSet(GDPlay.HpReason.BUFF);
        return doSubHp(action, actor, v , 0d, result);
    }

    //分摊伤害
    public DamageResult shareHurt(ActionCtx action, Fighter actor, Buff buff, double v) {
        DoubleRef doubleRef = new DoubleRef(v);
        owner.buff.getHandlers().forEach(h -> h.adjustShareDamage(action, actor, buff, doubleRef));
        return doSubHp(action, actor, v, 0d, new HpChangeResult().reasonSet(GDPlay.HpReason.SHARE_HURT));
    }

    //被动治疗
    public HealResult passiveHeal(ActionCtx action, double value) {
        return passiveHeal(action, owner, value);
    }

    //被动治疗
    public HealResult passiveHeal(ActionCtx action, Fighter actor, double value) {
        return heal(action, actor, value, false, GDPlay.HpReason.PASSIVE_SKILL_HEAL);
    }

    //由buff治疗
    public HealResult buffHeal(ActionCtx action,Fighter actor, double value) {
        return heal(action, actor, value,false,GDPlay.HpReason.BUFF);
    }
    //治疗
    public HealResult heal(ActionCtx action, Fighter actor, double value, boolean strike, int reason) {
        if (owner.buff.containType(GDBuff.Type.禁止受疗)) {
            return new HealResult();
        }
        return doAddHp(action, actor, value, new HpChangeResult().strikeSet(strike).reasonSet(reason));
    }

    //吸血
    public HealResult suck(ActionCtx action, Fighter actor, double doubleVal, int reason) {
        return doAddHp(action, actor, doubleVal, new HpChangeResult().reasonSet(reason));
    }

    /**
     * 复活
     * @param action
     * @param doubleVal
     * @return
     */
    public boolean resurrect(ActionCtx action, double doubleVal){
        return tryResurrect(action,doubleVal,false);
    }

    /**
     * 尝试复活
     * @param action
     * @param doubleVal
     * @param ignNoRebirth 无视禁活
     * @return
     */
    public boolean tryResurrect(ActionCtx action, double doubleVal, boolean ignNoRebirth) {
        if (this.owner.isAlive() || doubleVal <= 0) {
            return false;
        }
        if (this.owner.buff.containType(GDBuff.Type.禁止复活) && !ignNoRebirth) {
            return false;
        }
        if (!owner.allowChangeHp()) {
            return false;
        }
        doResurrect(action,doubleVal);
        owner.skill.forHandlers(a -> a.onResurrect(action));
        owner.buff.forHandlers(a -> a.onResurrect(action));
        return true;
    }

    /**
     * 复活的具体逻辑
     * @param action
     * @param doubleVal
     */
    public void doResurrect(ActionCtx action, double doubleVal) {
        owner.setDead(false);
        long hpChange = (long) doubleVal;
        double hpMax = total().hpTotal();
        this.hpCur(Math.min(hpChange, hpMax));
        ResurrectResult result = new ResurrectResult().pidSet(this.owner).valSet(hpChange).hpSet(hpCur());
        action.addResult(result);
    }

    /**
     * 斩杀
     * @param action
     * @param actor
     */
    public void kill(ActionCtx action, Fighter actor) {
        if (this.owner.isDead()) {
            return;
        }
        if (!owner.allowChangeHp()) {
            return;
        }
        FighterPerformance.recDamage(action, actor, owner, GDPlay.HpReason.SKILL_HURT, (long) hpCur());
        this.hpCur(0);
        action.addResult(new KillResult().pidSet(this.owner));
        this.owner.checkDead(action, actor);
    }


    /**
     * 最终加血的逻辑
     * @param action
     * @param v
     * @param result
     * @return
     */
    private HealResult doAddHp(ActionCtx action, Fighter actor, double v, HpChangeResult result) {
        HealResult healResult = new HealResult();
        if (v <= 0) {
            return healResult;
        }
        if (!owner.allowChangeHp()) {
            return healResult;
        }
        if (owner.isDead()) {
            return healResult;
        }
        //初始血量变更
        DoubleRef doubleRef = new DoubleRef(v);
        owner.buff.forHandlers(h -> h.adjustHeal(action, actor, doubleRef));
        long hpChange = (long) doubleRef.v;
        healResult.heal = hpChange;
        if (hpChange <= 0) {
            return healResult;
        }
        self.add(GDAttr.HP_CUR, hpChange);
        result.valSet(hpChange);
        //血量溢出修正
        healResult.overFlowHeal =  updateHp();
        result.pidSet(this.owner.pid).hpSet(self.hpCur());
        action.addResult(result);

        if (result.reason != GDPlay.HpReason.ATTR_SUCK) {
            //统计
            FighterPerformance.recHeal(action, actor, owner, hpChange);
        }
        return healResult;
    }

    /** 血量修正 */
    private long updateHp() {
        double hpMax = total().hpTotal();
        double hpCur = hpCur();
        if (hpCur > hpMax) {
            long overFlowHp =(long) (hpCur - hpMax);
            hpCur(hpMax);
            return overFlowHp;
        } else {
            return 0;
        }
    }

    /**
     * 最终扣血的逻辑
     * @param action
     * @param v
     * @param result
     * @return
     */
    private DamageResult doSubHp(ActionCtx action, Fighter actor, double v, double ignShieldRate, HpChangeResult result) {
        DamageResult damageResult = new DamageResult();
        if (v <= 0 || owner.isDead() || !owner.allowChangeHp()) {
            return damageResult;
        }
        //免疫检测
        for (BuffHandler handler : owner.buff.getHandlers()) {
            if (handler.hurtImmune(action, result.reason)) {
                return damageResult;
            }
        }
        //初始血量变更
        DoubleRef doubleRef = new DoubleRef(v);
        //被护盾吸收的伤害（也要算入总伤害）
        long absorb = 0;
        //护盾减免处理
        if (ignShieldRate < GD.W_10000_0) {
            //不能被护盾吸收的值
            double remainValue = 0d;
            if (ignShieldRate > 0) {
                //本次最大吸收值
                double absorbMax = owner.buff.shieldValue() * (1 - ignShieldRate / GD.W_10000_0);
                if (absorbMax < doubleRef.v) {
                    remainValue = doubleRef.v - absorbMax;
                    doubleRef.v = absorbMax;
                }
            }
            for (BuffHandler handler : this.owner.buff.getHandlers()) {
                absorb += handler.handleAbsorb(action, doubleRef);
                if (doubleRef.v <= 0) {
                    break;
                }
            }
            if (remainValue > 0) {
                doubleRef.v += remainValue;
            }
            if (absorb > 0) {
                damageResult.damage+=absorb;
                FighterPerformance.recDamage(action, actor, owner, result.reason, absorb);
                action.addResult(new ShieldChangeResult().pidSet(owner).valSet(-absorb).
                        hpSet(owner.buff.shieldValue()).reasonSet(GDPlay.ShieldReason.ABSORB));
                if (doubleRef.v <= 0) {
                    return damageResult;
                }
            }
        }

        for (PassiveHandler handler : this.owner.skill.getHandlers()) {
            if (doubleRef.v > 0) {
                handler.adjustDamage(action, actor,result.nature, result.reason, doubleRef);
            } else {
                break;
            }
        }

        if (result.nature != GDSkill.Nature.REAL) {
            //仅有物理、魔法的技能伤害可以被修正
            if (GDPlay.HpReason.SKILL_HURT == result.reason) {
                //伤害修正
                adjustSkillDamage(action, actor, result.reason, doubleRef);
                //伤害分摊
                this.owner.buff.forHandlers(a -> a.shareDamage(action, actor, result.reason, doubleRef));
            }
            //承受致死伤害时
            adjustDeadlyDamage(action, actor, result.reason, doubleRef);
        }
        //最终血量变更
        long hpChange = (long) doubleRef.v;
        if (hpChange > 0) {
            damageResult.damage += hpChange;
            self.add(GDAttr.HP_CUR, -hpChange);
            result.valSet(-hpChange);
            result.pidSet(this.owner.pid).hpSet(self.hpCur());
            action.addResult(result);
            FighterPerformance.recDamage(action, actor, owner, result.reason, hpChange);
            double hpCur = self.hpCur();
            if (hpCur < 0) {
                damageResult.overFlowDamage = -(long) hpCur;
            }
            this.owner.checkDead(action, actor);
        }
        return damageResult;
    }

    private void adjustSkillDamage(ActionCtx action, Fighter actor, int reason, DoubleRef doubleRef){
        for (PassiveHandler handler : this.owner.skill.getHandlers()) {
            if (doubleRef.v > 0) {
                handler.adjustSkillDamage(action, actor, reason, doubleRef);
            } else {
               return;
            }
        }
        for (BuffHandler handler : this.owner.buff.getHandlers()) {
            if (doubleRef.v > 0) {
                handler.adjustSkillDamage(action, actor, reason, doubleRef);
            } else {
                return;
            }
        }
    }

    private void adjustDeadlyDamage(ActionCtx action, Fighter actor, int reason, DoubleRef doubleRef) {
        for (PassiveHandler handler : this.owner.skill.getHandlers()) {
            if (doubleRef.v > hpCur()) {
                handler.adjustDeadlyDamage(action, actor, reason, doubleRef);
            } else {
                return;
            }
        }
        for (BuffHandler handler : this.owner.buff.getHandlers()) {
            if (doubleRef.v >= hpCur()) {
                handler.adjustDeadlyDamage(action, actor, reason, doubleRef);
            } else {
                return;
            }
        }
        //友方承受致死伤害时（包括自己）
        if (doubleRef.v >= hpCur()) {
            for (Fighter fighter : this.owner.getFightTeam().getFightersAlive()) {
                for (PassiveHandler handler : fighter.skill.getHandlers()) {
                    if (handler.adjustFriendDeadlyDamage(action, actor, owner, reason, doubleRef)) {
                        return;
                    }
                }
            }
        }
    }

    /** 获取单个属性的合计值 */
    public double getTotalValue(int type){
        return this.total().getTotalValue(type);
    }

    /**
     * 改变临时属性
     * @param attr
     */
    public void addAttr(FightAttr attr) {
        addAttr(attr,true,null );
    }

    /**
     * 改变临时属性
     * @param attr
     */
    public void addAttr(FightAttr attr, boolean add) {
        addAttr( attr, add,null);
    }

    /**
     * 改变临时属性
     * @param attr
     */
    public void addAttr(FightAttr attr, boolean add, ActionCtx action) {
        if (attr == null) {
            return;
        }
        if (add) {
            this.temp.add(attr);
        } else {
            this.temp.subtract(attr);
        }
        markCacheExpire(true);
        if (action != null && attr.containHpAttr()) {
            updateHp();
            action.addResult(new HpMaxChangeResult().pidSet(this.owner).hpSet(hpCur()).hpMaxSet(total().hpTotal()));
        }
    }

    public void onOwnerMoveOver(){
        move.clear();
        markCacheExpire(true);
    }

    public void addMoveAttr(FightAttr attr){
        addMoveAttr(attr, true);
    }

    public void addMoveAttr(FightAttr attr, boolean add) {
        if (add) {
            move.add(attr);
        } else {
            move.subtract(attr);
        }
        markCacheExpire(true);
    }
}
